#ifndef _ICELL_H
#define _ICELL_H

#include "point.h"

#include <iostream>
#include <vector>
#include <assert.h>

class VirtualICell;
typedef std::vector<VirtualICell*> ICellPtrVect;

// =============================================================================
//  Déclaration de la classe virtuelle i-cellule : VirtualICell
// =============================================================================

class VirtualICell
{
	public:
		// DESTRUCTEUR
		virtual ~VirtualICell() {}
		
		// GETTEUR
		virtual int GetDim() const = 0;
		virtual const ICellPtrVect* GetBorderCells() = 0;
		
		// AUTRES FONCTIONS
		virtual bool IsBorder(VirtualICell* iCell) { return false; }
		virtual void Display() = 0;
};

// =============================================================================
//  Déclaration de la classe i-cellule : ICell
//  Hérite de VirtualICell.
// =============================================================================

template<int t_iDimCell, int t_iDimPoint, typename t_Type>
class ICell : public VirtualICell
{
	public:
		// CONSTRUCTEUR / DESTRUCTEUR
		ICell(ICellPtrVect p_picBorderCells) : m_picBorderCells(p_picBorderCells) {}
		~ICell();
		
		// GETTEUR
		int GetDim() const { return t_iDimCell; }
		const ICellPtrVect* GetBorderCells() { return &m_picBorderCells; }
		
		// AUTRES FONCTIONS
		bool IsBorder(VirtualICell* iCell);
		void Display();

	private:
		ICellPtrVect m_picBorderCells;
};



// =============================================================================
//  Spécialisation de i-cellule pour les cellules de dimmension 0.
//  Hérite de VirtualICell.
// =============================================================================

template<int t_iDimPoint, typename t_Type>
class ICell<0, t_iDimPoint, t_Type> : public VirtualICell
{
	typedef Point<t_iDimPoint, t_Type> TPoint;
	
	public:
		// CONSTRUCTEUR / DESTRUCTEUR
		ICell(TPoint& p_pPoint) : m_pPoint(p_pPoint) {}
		~ICell() { delete &m_pPoint; }
		
		// GETTEUR
		int GetDim() const { return 0; }
		const ICellPtrVect* GetBorderCells() { return NULL; }
		const TPoint& GetPoint() const { return m_pPoint; }
		
		// AUTRES FONCTIONS
		void Display();
		
	private:
		TPoint& m_pPoint;
};

// =============================================================================
//  Implémentation des fonctions membres.
// =============================================================================

template<int t_iDimCell, int t_iDimPoint, typename t_Type>
ICell<t_iDimCell, t_iDimPoint, t_Type>::~ICell()
{
	for (int i = 0; i < m_picBorderCells.size(); i++)
		m_picBorderCells.pop_back();
}

// -----------------------------------------------------------------------------
template<int t_iDimCell, int t_iDimPoint, typename t_Type>
bool ICell<t_iDimCell, t_iDimPoint, t_Type>::IsBorder(VirtualICell* iCell)
{
	assert(iCell->GetDim() == t_iDimCell - 1);
	
	ICellPtrVect::iterator it;
	for (it = m_picBorderCells.begin(); it != m_picBorderCells.end(); ++it)
	{
		if (*it == iCell)
			return true;
	}
	return false;
}

// -----------------------------------------------------------------------------
template<int t_iDimCell, int t_iDimPoint, typename t_Type>
void ICell<t_iDimCell, t_iDimPoint, t_Type>::Display()
{
	std::cout << "Dimension " << t_iDimCell << std::endl;
	for (int i = 0; i < m_picBorderCells.size(); i++)
		m_picBorderCells[i]->Display();
}


// =============================================================================
//  Implémentation des fonctions membres.
//  Spécifique à la dimension 0.
// =============================================================================

template<int t_iDimPoint, typename t_Type>
void ICell<0, t_iDimPoint, t_Type>::Display()
{
	std::cout << "Dimension 0" << std::endl;
	for (int i = 0; i < t_iDimPoint; i++)
		std::cout << "point " << i << " : " << m_pPoint.GetCoordonate(i) << std::endl;
}

#endif // _ICELL_H
